package com.zyf.channel.plugin

import java.io.*
import java.util.zip.CRC32
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream

object ZipUtils {
    fun zipFolder(sourceDir: File, outputApk: File) {
        if (!sourceDir.exists() || !sourceDir.isDirectory) {
            throw FileNotFoundException("源目录不存在或不是文件夹：${sourceDir.absolutePath}")
        }
        if (outputApk.exists()) outputApk.delete()
        outputApk.parentFile?.mkdirs()

        ZipOutputStream(BufferedOutputStream(FileOutputStream(outputApk))).use { zos ->
            sourceDir.listFiles()?.forEach { file ->
                zipFileOrDir(zos, file, "")
            }
        }
    }

    private fun zipFileOrDir(zipOut: ZipOutputStream, file: File, baseDir: String) {
        val entryName = if (baseDir.isEmpty()) file.name else "$baseDir/${file.name}"

        if (file.isDirectory) {
            val dirEntryName = "$entryName/"
            zipOut.putNextEntry(ZipEntry(dirEntryName))
            zipOut.closeEntry()
            file.listFiles()?.forEach { child ->
                zipFileOrDir(zipOut, child, dirEntryName)
            }
        } else {
            if (entryName == "resources.arsc") {
                val fileBytes = file.readBytes()
                val crc32 = CRC32().apply { update(fileBytes) }

                val storedEntry = ZipEntry(entryName).apply {
                    method = ZipEntry.STORED
                    size = fileBytes.size.toLong()
                    compressedSize = fileBytes.size.toLong()
                    crc = crc32.value
                }

                zipOut.putNextEntry(storedEntry)
                zipOut.write(fileBytes)
                zipOut.closeEntry()
            } else {
                zipOut.putNextEntry(ZipEntry(entryName))
                BufferedInputStream(FileInputStream(file)).use { bis ->
                    val buffer = ByteArray(4096)
                    var count: Int
                    while (bis.read(buffer).also { count = it } != -1) {
                        zipOut.write(buffer, 0, count)
                    }
                }
                zipOut.closeEntry()
            }
        }
    }
}